package idv.takeshi.software.productline.bookstore.domain.model.order;

import java.util.Date;

import idv.takeshi.software.productline.bookstore.domain.model.book.Book;
import idv.takeshi.software.productline.bookstore.domain.model.book.Inventory;

import org.apache.commons.lang.Validate;

/**
 * A state pattern for OrderItem's status.
 * @author takeshi
 *
 */
public enum OrderItemStatus {
	
	/**
	 * A Ok status for orderItem.
	 * @author takeshi
	 */
	OK(){
		/**
		 * Do nothing.
		 */
		@Override
		public void checkReplenishmentCompleted(OrderItem thisOrderItem) {
			Validate.notNull(thisOrderItem, "thisOrderItem shall always not be null");
			//DO NOTHING
		}

		/* (non-Javadoc)
		 * @see idv.takeshi.software.productline.bookstore.domain.model.order.OrderItemStatus#checkReplenishmentNeeded(idv.takeshi.software.productline.bookstore.domain.model.order.OrderItem)
		 */
		@Override
		public void checkReplenishmentNeeded(OrderItem thisOrderItem) {
			Validate.notNull(thisOrderItem, "thisOrderItem shall always not be null");
			Book book = thisOrderItem.getOrderedBook();
			Validate.notNull(book, "book shall always not be null");
			Inventory inventory = book.getInventory();
			inventory.setWaitForShippingQuantity(thisOrderItem.getQuantity());
			if(inventory.needToReplenish()){
				thisOrderItem.setStatus(WAIT);
				thisOrderItem.setUpdateTime(new Date());
			}
		}

		/* (non-Javadoc)
		 * @see idv.takeshi.software.productline.bookstore.domain.model.order.OrderItemStatus#deliver(idv.takeshi.software.productline.bookstore.domain.model.order.OrderItem)
		 */
		@Override
		public void deliver(OrderItem thisOrderItem) {
			Validate.notNull(thisOrderItem, "thisOrderItem shall always not be null");
			thisOrderItem.setStatus(DELIVERED);
			thisOrderItem.setUpdateTime(new Date());
		}
		
	},
	
	/**
	 * A Wait status for orderItem.
	 * @author takeshi
	 *
	 */
	WAIT(){
		/* (non-Javadoc)
		 * @see idv.takeshi.software.productline.bookstore.domain.model.order.OrderItemStatus#checkReplenishmentCompleted(idv.takeshi.software.productline.bookstore.domain.model.order.OrderItem)
		 */
		@Override
		public void checkReplenishmentCompleted(OrderItem thisOrderItem) {
			Validate.notNull(thisOrderItem, "thisOrderItem shall always not be null");
			Book book = thisOrderItem.getOrderedBook();
			Validate.notNull(book, "book shall always not be null");
			Inventory inventory = book.getInventory();
			if(!inventory.needToReplenish()){
				thisOrderItem.setStatus(OK);
				thisOrderItem.setUpdateTime(new Date());
			}
		}
		
	},
	
	/**
	 * A Delivered status for orderItem.
	 */
	DELIVERED(){
		/* (non-Javadoc)
		 * @see idv.takeshi.software.productline.bookstore.domain.model.order.OrderItemStatus#cancel(idv.takeshi.software.productline.bookstore.domain.model.order.OrderItem)
		 */
		public void cancel(OrderItem thisOrderItem){
			throw new UnsupportedOperationException(INVALID_OPERATION);
		}
	};
 
	private static final String INVALID_OPERATION = "Invalid Operation";

	/**
	 * Check this orderItem whether need to be replenished.
	 * @param thisOrderItem
	 */
	public void checkReplenishmentNeeded(OrderItem thisOrderItem) {
		throw new UnsupportedOperationException(INVALID_OPERATION);
	}
	
	/**
	 * Check this replenished orderItem is whether replenished completed.
	 * @param thisOrderItem
	 */
	public void checkReplenishmentCompleted(OrderItem thisOrderItem) {
		throw new UnsupportedOperationException(INVALID_OPERATION);
	}
	 
	/**
	 * Deliver this orderItem.
	 * @param thisOrderItem
	 */
	public void deliver(OrderItem thisOrderItem) {
		throw new UnsupportedOperationException(INVALID_OPERATION);
	}
	
	/**
	 * Cancel this orderItem.
	 * @param thisOrderItem
	 */
	public void cancel(OrderItem thisOrderItem){
		Validate.notNull(thisOrderItem, "thisOrderItem shall always not be null");
		Book book = thisOrderItem.getOrderedBook();
		Validate.notNull(book, "book shall always not be null");
		Inventory inventory = book.getInventory();
		inventory.cancelWaitForShippingQuantity(thisOrderItem.getQuantity());
		
		thisOrderItem.setStatus(OK);
		thisOrderItem.setUpdateTime(new Date());
	}
	 
}
 
